package com.esdk.utils;

import com.esdk.esdk;
import com.esdk.sql.Exp;
import com.esdk.sql.Expression;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class EasyJdom{
  public static Document file2Doc(File xmlFile) throws Exception{
    SAXBuilder saxBuilder=new SAXBuilder();
    Document doc=saxBuilder.build(xmlFile);
    return doc;
  }

  public static Document str2Doc(String xmlStr) throws Exception{
    SAXBuilder saxBuilder=new SAXBuilder();
    Document doc=saxBuilder.build(new StringReader(xmlStr));
    return doc;
  }

  public static String doc2Str(Document doc) throws Exception{
    Format format=Format.getPrettyFormat();
    format.setEncoding("UTF-8");// 设置xml文件的字符为UTF-8，解决中文问题
    XMLOutputter xmlout=new XMLOutputter(format);
    ByteArrayOutputStream bo=new ByteArrayOutputStream();
    xmlout.output(doc,bo);
    return bo.toString();
  }

  public static Element str2Elment(String xmlStr) throws Exception{
    SAXBuilder saxBuilder=new SAXBuilder();
    Document doc=saxBuilder.build(new StringReader(xmlStr));
    return doc.getRootElement();
  }

  public static String element2Str(Element element) throws Exception{
    Format format=Format.getPrettyFormat();
    format.setEncoding("UTF-8");// 设置xml文件的字符为UTF-8，解决中文问题
    XMLOutputter xmlout=new XMLOutputter(format);
    ByteArrayOutputStream bo=new ByteArrayOutputStream();
    xmlout.output(element,bo);
    return bo.toString();
  }

  public static void doc2File(Document doc,File distFile) throws Exception{
    Format format=Format.getCompactFormat();
    format.setEncoding("UTF-8"); //设置XML文件的字符为UTF-8
    format.setIndent("     ");//设置缩进
    XMLOutputter outputter=new XMLOutputter(format);//定义输出 ,在元素后换行，每一层元素缩排四格
    FileWriter writer=new FileWriter(distFile);//输出流
    outputter.output(doc,writer);
    writer.close();
  }

  public static void doc2Stream(Document doc,OutputStream os) throws Exception{
    Format format=Format.getCompactFormat();
    format.setEncoding("UTF-8"); //设置XML文件的字符为UTF-8
    format.setIndent("  ");//设置缩进
    XMLOutputter outputter=new XMLOutputter(format);//定义输出 ,在元素后换行，每一层元素缩排四格
    outputter.output(doc,os);
    os.close();
  }

  public static void doc2Writer(Document doc,Writer writer) throws Exception{
    Format format=Format.getCompactFormat();
    format.setEncoding("UTF-8"); //设置XML文件的字符为UTF-8
    format.setIndent("  ");//设置缩进
    XMLOutputter outputter=new XMLOutputter(format);//定义输出 ,在元素后换行，每一层元素缩排四格
    outputter.output(doc,writer);
    writer.close();
  }

  /**
   * param doc: 必须是document，不能接受Element
   * param xpath: 例如：/xml/record[5]，注意数组从1开始，并非从0开始，如果有namespace，格式应为:/ns1:xml/ns1:record[5]，ns1是命名空间名称
   * 返回list
   */
  public static List<Element> getChildrenByXPath(Document doc,String xpath) throws JDOMException{
    List<Element> list=XPath.selectNodes(doc,xpath);
    return list;
  }

  public static Element getChildByXPath(Document doc,String xpath) throws JDOMException{
    Element result=(Element)XPath.selectSingleNode(doc,xpath);
    return result;
  }

  public static List<Element> getChildren(Element parent,String name){
    return getChildren(parent,name,null);
  }

  public static List<Element> getChildren(Element parent,String name,String namespace){
    List<Element> result=new ArrayList<>();
    for(Object item: parent.getChildren()){
      if(item instanceof Element){
        Element child=(Element)item;
        if(child.getName().equalsIgnoreCase(name)&&(namespace==null||child.getNamespace().getPrefix().equals(namespace)))
          result.add(child);
      }
    }
    return result;
  }

  public static Element getChild(Element parent,String name,String namespace){
    for(Object item: parent.getChildren()){
      if(item instanceof Element){
        Element child=(Element)item;
        if(child.getName().equalsIgnoreCase(name)&&(namespace==null||child.getNamespace().getPrefix().equals(namespace)))
          return child;
      }
    }
    return null;
  }

  public static List<Element> getChildrenByPath(Element parent,String path){
    return getChildrenByPath(parent,path,false);
  }

  public static List<Element> getChildrenByPath(Element parent,String path,boolean ignoreNamespace){
    List<Element> result=new ArrayList<>();
    if(path.startsWith("/"))
      path=path.substring(1);
    String[] paths=esdk.str.splitFirst(path,"/");
    if(esdk.array.isEmpty(paths))
      return result;
    String currentPath=paths[0];
    List<Element> tempList=new ArrayList<>();
    if(esdk.str.existAnd(currentPath,":,[,]".split(","))){
      String[] arr=esdk.regex.findSubs(currentPath,"(.+?):(.+?)\\[(\\d+)\\]");
      String namespace=arr[0];
      String childname=arr[1];
      int index=Integer.valueOf(arr[2]);
      tempList.add(getChildren(parent,childname,ignoreNamespace?null:namespace).get(index));
    }else if(esdk.str.existAnd(currentPath,"[,]".split(","))){
      String[] arr=esdk.regex.findSubs(currentPath,"(.+?)\\[(\\d+)\\]");
      String childname=arr[0];
      int index=Integer.valueOf(arr[1]);
      tempList.add(getChildren(parent,childname,null).get(index));
    }else if(currentPath.contains(":")){
      String[] name_space=esdk.str.splitFirst(currentPath,":");
      tempList=getChildren(parent,name_space[1],ignoreNamespace?null:name_space[0]);
    }else if(currentPath.length()>1){
      tempList=getChildren(parent,currentPath);
    }else if(currentPath.equals("")){
      tempList=parent.getChildren();
    }
    if(paths.length>1){
      String subPath=paths[1];
      for(Element item1: tempList){
        result.addAll(getChildrenByPath(item1,subPath,ignoreNamespace));
      }
    }else{
      result=tempList;
    }
    return result;
  }

  public static Element getChildByPath(Element parent,String path) {
    return getChildByPath(parent,path,true);
  }
  public static Element getChildByPath(Element parent,String path,boolean ignoreNamespace){
    List<Element> list=getChildrenByPath(parent,path,ignoreNamespace);
    return list.isEmpty()?null:list.get(0);
  }

  public static boolean findText(Element element,String exp,String keyword){
    if(element.getText().length()>0){
      Expression express=new Expression(element.getValue(),exp,keyword);
      return express.compute();
    }
    return false;
  }

  public static List<Element> findText(Element parent,String exp,String keyword,ArrayList<Element> resultList) throws JDOMException{
    ArrayList<Element> result=resultList!=null?resultList:new ArrayList<>();
    if(findText(parent,exp,keyword))
      result.add(parent);
    for(Element item:(List<Element>)parent.getChildren()){
      if(findText(item,exp,keyword))
        result.add(item);
      for(Element item1:(List<Element>)item.getChildren())
        findText(item1,exp,keyword,result);
    }
    return result;
  }

  public static List<Element> findText(Element parent,String keyword) throws JDOMException{
    return findText(parent,Exp.EQUAL,keyword,null);
  }

  public static void main(String[] args) throws Exception{
    File xmlFile=new File("./testfiles/设备输出报告_${nowDate}_(${name}).doc");
    esdk.tool.assertEquals(xmlFile.exists());
    Document doc=esdk.jdom.file2Doc(xmlFile);
    Namespace ns=doc.getRootElement().getNamespace();
    Element element=doc.getRootElement().getChild("part",ns);
    String xmlStr=EasyJdom.element2Str(element);
    esdk.tool.assertEquals(xmlStr.contains("pkg:xmlData"));
    List<Element> list=getChildrenByXPath(doc,"/pkg:package/pkg:part");
    esdk.tool.assertEquals(list.size()>3);
    List<Element> list1=getChildrenByPath(list.get(2),"/pkg:xmlData/w:document/w:body/w:tbl/w:tr[3]");
    esdk.tool.assertEquals(list1.size(),1);
    for(Element item: list1){
      esdk.tool.assertEquals(!element2Str(item).contains("pkg:part"));
    }
    Element filter=getChildByPath(list.get(2),"/xmlData/document/body/tbl/tr[7]",true);
    esdk.tool.assertEquals(element2Str(filter).contains("通话功能"));
    List<Element> list2=findText(doc.getRootElement(),"通话功能");
    esdk.tool.assertEquals(list2.size(),1);
    list2.get(0).setText("通讯功能");
    doc2File(doc,esdk.file.appendMiddleExt(xmlFile,"output"));
    File xmlFile1=new File("./testfiles/orm_relationship.xml");
    Document doc1=file2Doc(xmlFile1);
//    esdk.sout(doc2Str(doc1));
    Element child=getChildByXPath(doc1,"/xml/record[5]");
    child.setText("测试修改节点");
    doc2File(doc1,esdk.file.appendMiddleExt(xmlFile1,"output"));
    esdk.tool.printAssertInfo();
  }
}
